﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 异步工具类
{
    /// <summary>
    /// 异步工具类
    /// </summary>
    public class TaskTools
    {
        /// <summary>
        /// 是否 在执行回调函数之前修改Running状态
        /// </summary>
        public bool ChangeRunningStateBeforeCallback { get; private set; }

        /// <summary>
        /// 是否 正在执行异步任务
        /// </summary>
        public bool Running { get; private set; }


        public TaskTools()
            : this(false)
        {

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="changeRunningStateBeforeCallback">是否 在执行回调函数之前修改Running状态 默认值false</param>
        public TaskTools(bool changeRunningStateBeforeCallback)
        {
            this.ChangeRunningStateBeforeCallback = changeRunningStateBeforeCallback;
        }

        /// <summary>
        /// 执行异步任务
        /// </summary>
        /// <typeparam name="T">异步任务返回值类型</typeparam>
        /// <param name="control">操作UI时需要Invoke的控件</param>
        /// <param name="asyncFunc">将要执行的任务任务</param>
        /// <param name="callback">异步任务执行完毕后执行的回调函数</param>
        public void Run<T>(Control control, Func<T> asyncFunc, Action<T> callback)
        {
            if (this.Running)
                throw new InvalidOperationException(" the task is running ");
            try
            {
                this.Running = true;
                Task<T> task = new Task<T>(() =>
                {
                    try
                    {
                        return asyncFunc();
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        return default(T);
                    }
                });

                task.Start();

                TaskContinue<T>(control, task, callback);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                this.Running = false;
            }
        }


        /// <summary>
        /// 执行异步任务
        /// </summary>
        /// <typeparam name="T">异步任务返回值类型</typeparam>
        /// <param name="control">操作UI时需要Invoke的控件</param>
        /// <param name="args">异步任务的传入参数</param>
        /// <param name="asyncFunc">将要执行的任务任务</param>
        /// <param name="callback">异步任务执行完毕后执行的回调函数</param>
        public void Run<T>(Control control, object args, Func<object, T> asyncFunc, Action<T> callback)
        {
            if (this.Running)
                throw new InvalidOperationException(" the task is running ");

            try
            {
                this.Running = true;
                Task<T> task = new Task<T>((lambdaObj) =>
                {
                    try
                    {
                        return asyncFunc(lambdaObj);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                        return default(T);
                    }
                }, args);

                task.Start();

                TaskContinue<T>(control, task, callback);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                this.Running = false;
            }
        }


        /// <summary>
        /// 延时执行某任务
        /// </summary>
        /// <param name="control">操作UI时需要Invoke的控件</param>
        /// <param name="milliSecond">将要延时执行的毫秒数</param>
        /// <param name="callback">异步任务执行完毕后执行的回调函数</param>
        public void DelayedRun(int milliSecond, Control control, Action callback)
        {
            this.Run<int>(control, () =>
            {
                Thread.Sleep(milliSecond); // 4.0 类库
                return milliSecond;
            }, (time) =>
            {
                callback();
            });
        }


        /// <summary>
        /// Control.Invoke方法的简易封装
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="control"></param>
        /// <param name="args"></param>
        /// <param name="action"></param>
        public static void ControlInvoke<T>(Control control, T args, Action<T> action)
        {
            try
            {
                Invoke<T>(control, args, action);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 异步任务完成后继续执行...
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="control"></param>
        /// <param name="task"></param>
        /// <param name="callback"></param>
        private void TaskContinue<T>(Control control, Task<T> task, Action<T> callback)
        {
            task.ContinueWith((lambdaAction) =>
            {
                if (this.ChangeRunningStateBeforeCallback)
                {
                    this.Running = false;
                }
                try
                {
                    if (callback != null)
                    {
                        // 有UI控件 则将回调函数 注入到UI控件的相关线程中去执行
                        if (control != null)
                        {
                            TaskTools.Invoke<T>(control, lambdaAction.Result, callback);
                        }
                        else
                        {
                            // 否则在当前线程内执行 回调函数
                            callback(lambdaAction.Result);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                finally
                {
                    this.Running = false;
                }
            });
        }

        /// <summary>
        /// Control.Invoke方法的简易封装
        /// 注意 无 Try Catch
        /// </summary>
        /// <typeparam name="T">参数类型</typeparam>
        /// <param name="control"></param>
        /// <param name="args"></param>
        /// <param name="action"></param>
        private static void Invoke<T>(Control control, T args, Action<T> action)
        {
            // control为空，在当前线程内执行该action
            if (control == null)
            {
                action(args);
                return;
            }

            // 控件正在释放或者已经被释放则不执行action
            if (control.Disposing || control.IsDisposed)
                return;

            if (control.InvokeRequired)
            {
                control.Invoke(action, new object[] {args});
            }
            else
            {
                action(args);
            }
        }
    }
}
